// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.TestModels.MusicStore;

public class ShoppingCart
{
    private readonly MusicStoreContext _dbContext;
    private readonly string _shoppingCartId;

    private ShoppingCart(MusicStoreContext dbContext, string id)
    {
        _dbContext = dbContext;
        _shoppingCartId = id;
    }

    public static ShoppingCart GetCart(MusicStoreContext db, string cartId)
        => new(db, cartId);

    public async Task AddToCart(Album album)
    {
        // Get the matching cart and album instances
        var cartItem = await _dbContext.CartItems.SingleOrDefaultAsync(
            c => c.CartId == _shoppingCartId
                && c.AlbumId == album.AlbumId);

        if (cartItem == null)
        {
            // Create a new cart item if no cart item exists
            cartItem = new CartItem
            {
                AlbumId = album.AlbumId,
                CartId = _shoppingCartId,
                Count = 1,
                DateCreated = DateTime.Now
            };

            _dbContext.CartItems.Add(cartItem);
        }
        else
        {
            // If the item does exist in the cart, then add one to the quantity
            cartItem.Count++;
        }
    }

    public int RemoveFromCart(int id)
    {
        // Get the cart
        var cartItem = _dbContext.CartItems.SingleOrDefault(
            cart => cart.CartId == _shoppingCartId
                && cart.CartItemId == id);

        var itemCount = 0;

        if (cartItem != null)
        {
            if (cartItem.Count > 1)
            {
                cartItem.Count--;
                itemCount = cartItem.Count;
            }
            else
            {
                _dbContext.CartItems.Remove(cartItem);
            }
        }

        return itemCount;
    }

    public async Task EmptyCart()
    {
        var cartItems = await _dbContext
            .CartItems
            .Where(cart => cart.CartId == _shoppingCartId)
            .ToArrayAsync();

        _dbContext.CartItems.RemoveRange(cartItems);
    }

    public Task<List<CartItem>> GetCartItems()
        => _dbContext
            .CartItems
            .Where(cart => cart.CartId == _shoppingCartId)
            .Include(c => c.Album)
            .ToListAsync();

    public Task<List<string>> GetCartAlbumTitles()
        => _dbContext
            .CartItems
            .Where(cart => cart.CartId == _shoppingCartId)
            .Select(c => c.Album.Title)
            .OrderBy(n => n)
            .ToListAsync();

    public Task<int> GetCount()
        // Get the count of each item in the cart and sum them up
        => _dbContext
            .CartItems
            .Where(c => c.CartId == _shoppingCartId)
            .Select(c => c.Count)
            .SumAsync();

    public async Task<decimal> GetTotal()
        // Multiply album price by count of that album to get
        // the current price for each of those albums in the cart
        // sum all album price totals to get the cart total
        // No way to do decimal sum on server with SQLite, but client eval is fine here
        => (await _dbContext
                .CartItems
                .Where(c => c.CartId == _shoppingCartId)
                .Select(c => c.Album.Price * c.Count)
                .ToListAsync())
            .Sum();

    public async Task CreateOrder(Order order)
    {
        decimal orderTotal = 0;

        var cartItems = await GetCartItems();

        // Iterate over the items in the cart, adding the order details for each
        foreach (var item in cartItems)
        {
            //var album = _db.Albums.Find(item.AlbumId);
            var album = await _dbContext.Albums.SingleAsync(a => a.AlbumId == item.AlbumId);

            var orderDetail = new OrderDetail
            {
                AlbumId = item.AlbumId,
                Order = order,
                UnitPrice = album.Price,
                Quantity = item.Count
            };

            // Set the order total of the shopping cart
            orderTotal += (item.Count * album.Price);

            _dbContext.OrderDetails.Add(orderDetail);
        }

        // Set the order's total to the orderTotal count
        order.Total = orderTotal;

        // Empty the shopping cart
        await EmptyCart();
    }
}
